﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace HexEditor_
{
    public abstract class HexDoc
    {
        public FormatMarkManager FormatData { get; set; }
        
        public string FilePath { get; set; }
        public abstract Int64 GetByteCount();

        //从offset开始获取count个byte, 实际获取的字节数组，offset count会被修改为返回数组对应的起点索引和长度
        public abstract byte[] GetBytes(ref Int64 offset, ref int count);

        //实现打开
        public bool Open(string path)
        {
            if (OpenConcrete(path))
            {
                FormatData = new FormatMarkManager();
                FormatData.Initialize();
                return true;
            }
            return false;
        }

        public int Close()
        { 
            return 0; 
        }

        protected abstract bool OpenConcrete(string path);

        public int SetFormatRange(HexEditor editor, string typename, Int64 begin, Int64 end)
        {
            if (begin < 0)
                begin = 0;
            if (end < 0 || end > GetByteCount())
                end = GetByteCount();
            if (begin > end)
            {
                var s = end;
                end = begin;
                begin = s;
            }
            if (begin == end)
                return 0;

            return FormatData.SetFormatRange(editor, typename, begin, end);
        }

        public int GetFormatMarkPos(Int64 offset, int findFrom)
        {
            if(findFrom + 1 < FormatData.FormatMarkList.Count)
            {
                if (FormatData.FormatMarkList[findFrom + 1].Offset > offset)
                    return findFrom;
                return GetFormatMarkPos(offset, findFrom + 1);
            }
            return findFrom;
        }
        public FormatMark GetFormatMark(int pos)
        {
            return FormatData.FormatMarkList[pos];
        }

        public bool IsItemStart(Int64 offset, ref DataTypeManager dtManager)
        {
            return FormatData.IsFormatItemStart(offset, ref dtManager);
        }

        public bool IsItemStart(Int64 offset, int formatPos, ref DataTypeManager dtManager)
        {
            return FormatData.IsFormatItemStart(offset, ref dtManager);
        }

        public string ParseItem(byte[] data, int offsetindata, out int parsedLen, int formatPos,
            ref DataTypeManager dtManager)
        {
            string str;
            parsedLen = dtManager.Parse(data, offsetindata, 
                FormatData.FormatMarkList[formatPos].DataTypeName, out str);
            return str;
        }
    }

    public class HexDocNormal : HexDoc
    {
        byte[] _FileData;

        protected override bool OpenConcrete(string path)
        {
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);

            if (fs.Length > Int32.MaxValue / 2)
            {
                throw new Exception("File too big for normal hex doc");
            }

            _FileData = new byte[fs.Length];

            if (fs.Read(_FileData, 0, (int)fs.Length) == fs.Length)
            {
                fs.Close();
                return true;
            }
            fs.Close();
            return false;
        }

        public override Int64 GetByteCount()
        {
            return _FileData == null ? 0 : _FileData.Length ;
        }

        public override byte[] GetBytes(ref Int64 offset, ref int count)
        {
            offset = 0;
            count = (int)GetByteCount();
            return _FileData;
        }
    }
}
